package com.ywl5320.myplayer.player;

import android.media.MediaCodec;
import android.media.MediaFormat;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.text.TextUtils;
import android.view.Surface;

import com.ywl5320.myplayer.WlTimeInfoBean;
import com.ywl5320.myplayer.codec.WlMediaCodec;
import com.ywl5320.myplayer.listener.WlOnCompleteListener;
import com.ywl5320.myplayer.listener.WlOnErrorListener;
import com.ywl5320.myplayer.listener.WlOnLoadListener;
import com.ywl5320.myplayer.listener.WlOnParparedListener;
import com.ywl5320.myplayer.listener.WlOnPauseResumeListener;
import com.ywl5320.myplayer.listener.WlOnRenderYUVListener;
import com.ywl5320.myplayer.listener.WlOnTimeInfoListener;
import com.ywl5320.myplayer.log.MyLog;
import com.ywl5320.myplayer.opengl.WlGLSurfaceView;
import com.ywl5320.myplayer.opengl.WlRender;
import com.ywl5320.myplayer.util.WlCodecSupportUtil;

import java.nio.ByteBuffer;

/**
 * Created by yangw on 2018-2-28.
 */

public class WlPlayer {

    static {
        System.loadLibrary("native-lib");
        System.loadLibrary("avcodec-57");
        System.loadLibrary("avdevice-57");
        System.loadLibrary("avfilter-6");
        System.loadLibrary("avformat-57");
        System.loadLibrary("avutil-55");
        System.loadLibrary("postproc-54");
        System.loadLibrary("swresample-2");
        System.loadLibrary("swscale-4");
    }

    private static String source;//数据源
    private static WlTimeInfoBean wlTimeInfoBean;
    private static boolean playNext = false;
    private WlOnParparedListener wlOnParparedListener;
    private WlOnLoadListener wlOnLoadListener;
    private WlOnPauseResumeListener wlOnPauseResumeListener;
    private WlOnTimeInfoListener wlOnTimeInfoListener;
    private WlOnErrorListener wlOnErrorListener;
    private WlOnCompleteListener wlOnCompleteListener;
    private WlOnRenderYUVListener wlOnRenderYUVListener;
    private int duration;
    private WlMediaCodec wlMediaCodec;
    private WlGLSurfaceView wlGLSurfaceView;
    private Surface surface;
    private MediaFormat mediaFormat;
    private MediaCodec mediaCodec;
    private MediaCodec.BufferInfo info;

    public WlPlayer() {
    }

    /**
     * 设置数据源
     *
     * @param source
     */
    public void setSource(String source) {
        this.source = source;
    }

    public void setWlGLSurfaceView(WlGLSurfaceView wlGLSurfaceView) {
        this.wlGLSurfaceView = wlGLSurfaceView;
        wlGLSurfaceView.getWlRender().setOnSurfaceCreateListener(new WlRender.OnSurfaceCreateListener() {
            @Override
            public void onSurfaceCreate(Surface s) {
                if(surface == null)
                {
                    surface = s;
                    MyLog.d("onSurfaceCreate");
                }
            }
        });
    }

    /**
     * 设置准备接口回调
     *
     * @param wlOnParparedListener
     */
    public void setWlOnParparedListener(WlOnParparedListener wlOnParparedListener) {
        this.wlOnParparedListener = wlOnParparedListener;
    }

    public void setWlOnLoadListener(WlOnLoadListener wlOnLoadListener) {
        this.wlOnLoadListener = wlOnLoadListener;
    }

    public void setWlOnPauseResumeListener(WlOnPauseResumeListener wlOnPauseResumeListener) {
        this.wlOnPauseResumeListener = wlOnPauseResumeListener;
    }

    public void setWlOnTimeInfoListener(WlOnTimeInfoListener wlOnTimeInfoListener) {
        this.wlOnTimeInfoListener = wlOnTimeInfoListener;
    }

    public void setWlOnErrorListener(WlOnErrorListener wlOnErrorListener) {
        this.wlOnErrorListener = wlOnErrorListener;
    }

    public void setWlOnCompleteListener(WlOnCompleteListener wlOnCompleteListener) {
        this.wlOnCompleteListener = wlOnCompleteListener;
    }

    public void setWlOnRenderYUVListener(WlOnRenderYUVListener wlOnRenderYUVListener) {
        this.wlOnRenderYUVListener = wlOnRenderYUVListener;
    }

    public void parpared() {
        if (TextUtils.isEmpty(source)) {
            MyLog.d("source not be empty");
            return;
        }
        new Thread(new Runnable() {
            @Override
            public void run() {
                n_parpared(source);
            }
        }).start();

    }

    public void start() {
        if (TextUtils.isEmpty(source)) {
            MyLog.d("source is empty");
            return;
        }
        new Thread(new Runnable() {
            @Override
            public void run() {
                n_start();
            }
        }).start();
    }

    public void pause() {
        n_pause();
        if (wlOnPauseResumeListener != null) {
            wlOnPauseResumeListener.onPause(true);
        }
    }

    public void resume() {
        n_resume();
        if (wlOnPauseResumeListener != null) {
            wlOnPauseResumeListener.onPause(false);
        }
    }

    public void stop() {
        wlTimeInfoBean = null;
        new Thread(new Runnable() {
            @Override
            public void run() {
                n_stop();
                releaseMediacodec();
            }
        }).start();
    }

    public void seek(int secds) {
        n_seek(secds);
    }

    public void playNext(String url) {
        source = url;
        playNext = true;
        stop();
    }


    /**
     * c++回调java的方法
     */
    public void onCallParpared() {
        if (wlOnParparedListener != null) {
            wlOnParparedListener.onParpared();
        }
    }

    public void onCallLoad(boolean load) {
        if (wlOnLoadListener != null) {
            wlOnLoadListener.onLoad(load);
        }
    }

    public void onCallTimeInfo(int currentTime, int totalTime) {
        if (wlOnTimeInfoListener != null) {
            if (wlTimeInfoBean == null) {
                wlTimeInfoBean = new WlTimeInfoBean();
            }
            duration = totalTime;
            wlTimeInfoBean.setCurrentTime(currentTime);
            wlTimeInfoBean.setTotalTime(totalTime);
            wlOnTimeInfoListener.onTimeInfo(wlTimeInfoBean);
        }
    }

    public void onCallError(int code, String msg) {
        if (wlOnErrorListener != null) {
            stop();
            wlOnErrorListener.onError(code, msg);
        }
    }

    public void onCallComplete() {
        if (wlOnCompleteListener != null) {
            stop();
            wlOnCompleteListener.onComplete();
        }
    }

    public void onCallNext() {
        if (playNext) {
            playNext = false;
            parpared();
        }
    }

    public void onCallRenderYuv(int width, int height, byte[] yuv_y, byte[] yuv_u, byte[] yuv_v) {
        MyLog.d("获取到视频的yuv数据");
        if(wlGLSurfaceView != null)
        {
            wlGLSurfaceView.getWlRender().setRenderType(WlRender.RENDER_YUV);
            wlGLSurfaceView.setYUVData(width, height, yuv_y, yuv_u, yuv_v);
        }
    }


    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
    public void onCallInitMediacodec(String codecName, int width, int height, byte[] csd_0, byte[] csd_1) {
        if(surface != null)
        {
            try {
                wlGLSurfaceView.getWlRender().setRenderType(WlRender.RENDER_MEDIACODEC);
                String mime = WlCodecSupportUtil.findSupportCodec(codecName);
                mediaFormat = MediaFormat.createVideoFormat(mime, width, height);
                mediaFormat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, width * height);
                mediaFormat.setByteBuffer("csd-0", ByteBuffer.wrap(csd_0));
                mediaFormat.setByteBuffer("csd-1", ByteBuffer.wrap(csd_1));
                MyLog.d(mediaFormat.toString());
                mediaCodec = MediaCodec.createDecoderByType(mime);

                info = new MediaCodec.BufferInfo();
                mediaCodec.configure(mediaFormat, surface, null, 0);
                mediaCodec.start();

            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
        }
        else
        {
            if(wlOnErrorListener != null)
            {
                wlOnErrorListener.onError(2001, "surface is null");
            }
        }
    }

    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
    public boolean onCallSupportCodec(String codecName) {
        return WlCodecSupportUtil.isSupportCodec(codecName);
    }

    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
    public void onCallDecode(int datasize, byte[]data){
        if(surface != null && datasize > 0 && data != null && mediaCodec != null)
        {
            try {
                int intputBufferIndex = mediaCodec.dequeueInputBuffer(10);
                if(intputBufferIndex >= 0)
                {
                    ByteBuffer byteBuffer = mediaCodec.getInputBuffers()[intputBufferIndex];
                    byteBuffer.clear();
                    byteBuffer.put(data);
                    mediaCodec.queueInputBuffer(intputBufferIndex, 0, datasize, 0, 0);
                }
                int outputBufferIndex = mediaCodec.dequeueOutputBuffer(info, 10);
                while(outputBufferIndex >= 0)
                {
                    mediaCodec.releaseOutputBuffer(outputBufferIndex, true);
                    outputBufferIndex = mediaCodec.dequeueOutputBuffer(info, 10);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    private void releaseMediacodec()
    {
        if(mediaCodec != null)
        {

            try {
                mediaCodec.stop();
                mediaCodec.release();

                mediaCodec = null;
                mediaFormat = null;
                info = null;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    }
    private native void n_parpared(String source);

    private native void n_start();

    private native void n_pause();

    private native void n_resume();

    private native void n_stop();

    private native void n_seek(int secds);


    public int getduration() {

        return duration;
    }
}
